package cn.wind.xboot;

import cn.wind.xboot.conf.config.XbootConfiguration;
import cn.wind.xboot.framework.filter.DecryptFilter;
import cn.wind.xboot.framework.filter.RequestFilter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.wind.encrypt.anno.EnableEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;

/**
 * @author xukk
 */
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableCaching
@EnableEncrypt
public class XbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(XbootApplication.class, args);
    }

    @Component
    public class MyStartupRunner1 implements CommandLineRunner {

        @Override

        public void run(String... args) throws Exception {
            log.info("初始化一些操作....");
        }

    }

    @Autowired
    private XbootConfiguration xbootConfiguration;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @SuppressWarnings("unchecked")
    @PostConstruct
    public void post() {
        //Long类型会出现异常信息;需要我们上面的自定义key生成策略，一般没必要
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        //定义value的序列化方式
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
    }

    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
                if (o instanceof List || o instanceof Set || o instanceof Array) {
                    jsonGenerator.writeStartArray();
                    jsonGenerator.writeEndArray();
                } else {
                    jsonGenerator.writeString("");
                }

            }
        });
        return objectMapper;
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return jacksonObjectMapperBuilder ->
                jacksonObjectMapperBuilder.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
                        .timeZone(TimeZone.getTimeZone("GMT+8"))
                        .failOnUnknownProperties(false)
                        .failOnEmptyBeans(false);
    }


    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


    @Bean
    public FilterRegistrationBean requestFilterRegistration() {
        RequestFilter requestFilter=new RequestFilter();
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(requestFilter);
        registration.addUrlPatterns("/*");
        registration.setName("requestFilter");
        registration.setOrder(requestFilter.getOrder());
        return registration;
    }

    @Bean
    public FilterRegistrationBean decryptFilterFilterRegistration() {
        DecryptFilter decryptFilter=new DecryptFilter(stringRedisTemplate,"/api/**");
        decryptFilter.setTimeLimit(xbootConfiguration.getFilter().getInvalidTime());
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(decryptFilter);
        registration.addUrlPatterns("/*");
        registration.setName("decryptFilter");
        registration.setOrder(decryptFilter.getOrder());
        return registration;
    }

}
